Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(loadtest): uniswapv3 loadtest #137

Merged
merged 189 commits into from
Oct 20, 2023
Merged

Conversation

leovct
Copy link
Member

@leovct leovct commented Oct 18, 2023

Description

Follow-up of #122

One thing to note is that the first swap will always revert with replacement transaction underpriced.

11:50AM TRC Finished starting go routines. Waiting..
11:50AM ERR Unable to swap error="replacement transaction underpriced" tokenIn=token0 tokenOut=token1
11:50AM ERR Recorded an error while sending transactions error="replacement transaction underpriced" nonce=417
11:50AM TRC Request mode=loadTestModeUniswapV3 nonce=417 request=0 routine=0
11:50AM DBG Successful swap tokenIn=token1 tokenOut=token0
11:50AM TRC Transaction hash=0x77c39c3c316c47e9ae511df615e404fcc9ab9f69f90f30399c7556484b70f76c
11:50AM TRC Request mode=loadTestModeUniswapV3 nonce=418 request=1 routine=0
11:50AM DBG Successful swap tokenIn=token0 tokenOut=token1
11:50AM TRC Transaction hash=0x9fadc0258c636cc0ac26db0110e3d93b806cd93a0d90f30e44d4c6a8fbafa5e4
11:50AM TRC Request mode=loadTestModeUniswapV3 nonce=419 request=2 routine=0
11:50AM DBG Successful swap tokenIn=token1 tokenOut=token0
11:50AM TRC Transaction hash=0xa8ebe88ebde1e0cbedcf36d101a5f6d1338bf69fe3c22a7440a59ee78deee9f1

Jira Ticket

Test

Here's the full log of a uniswapv3 loadtest.

$ go run main.go loadtest uniswapv3 --verbosity 500 http://localhost:8545 --requests 20 --swap-amount 100000 --pool-fees 1
1:17PM DBG Starting logger in console mode
1:17PM INF Starting Load Test
1:17PM INF Connecting with RPC endpoint to initialize load test parameters
1:17PM DBG eip-1559 support detected
1:17PM DBG 🦄 Deploying UniswapV3 contracts...
1:17PM DBG Step 0: WETH9 deployment
1:17PM DBG Contract deployed address=0x30ab089a1fd09798e331f65137c000e3cec3d0bc name=WETH9
1:17PM DBG Step 1: UniswapV3Factory deployment
1:17PM DBG Contract deployed address=0x517b35c144592801d8c91da672fe6beb72dbd53c name=UniswapV3Factory
1:17PM DBG Step 2: Enable fee amount
1:17PM DBG Fee amount enabled
1:17PM DBG Step 3: UniswapInterfaceMulticall deployment
1:17PM DBG Contract deployed address=0xd05c6a5916d505210fd23d45ba01764e0f51f68d name=UniswapInterfaceMulticall
1:17PM DBG Step 4: ProxyAdmin deployment
1:17PM DBG Contract deployed address=0x1e8eab39bb35a8e7fad0e83a8e58f8098d9e42cc name=ProxyAdmin
1:17PM DBG Step 5: TickLens deployment
1:17PM DBG Contract deployed address=0xe16e25481168566a464283ad5c00499db046fbce name=TickLens
1:17PM DBG Step 6: NFTDescriptorLib deployment
1:17PM DBG Contract deployed address=0xd1aeb77784e6c963a53745f4ff987265e2eeb0d9 name=NFTDescriptor
1:17PM DBG Step 7: NFTPositionDescriptor deployment
1:17PM DBG Contract deployed address=0x835b6433ffe0a67f2b0dc8c3be87d2c0594c985d name=NonfungibleTokenPositionDescriptor
1:17PM DBG Step 8: TransparentUpgradeableProxy deployment
1:17PM DBG Contract deployed address=0xd65144402b5162fc77a445d453d38ffcb7eeb54d name=TransparentUpgradeableProxy
1:17PM DBG Step 9: NonfungiblePositionManager deployment
1:17PM DBG Contract deployed address=0xed7b53de74e6fde98cf89e430a2a35871e34235a name=NonfungiblePositionManager
1:17PM DBG Step 10: V3Migrator deployment
1:17PM DBG Contract deployed address=0xcde48557ee1e70f8d662cf5c1aa731802253f414 name=V3Migrator
1:17PM DBG Step 11: Transfer UniswapV3Factory ownership
1:17PM DBG Factory contract already owned by this address
1:17PM DBG Step 12: UniswapV3Staker deployment
1:17PM DBG Contract deployed address=0x3bb4c7ef05800ec62dc80e8dd0ed914cfadabee1 name=UniswapV3Staker
1:17PM DBG Step 13: QuoterV2 deployment
1:17PM DBG Contract deployed address=0x758a62abdbcabe2742164044e8cef24d9f962763 name=QuoterV2
1:17PM DBG Step 14: SwapRouter02 deployment
1:17PM DBG Contract deployed address=0x09a1a871258aac7c894ecb3116fd1482b0a52c62 name=SwapRouter02
1:17PM DBG Step 15: Transfer ProxyAdmin ownership
1:17PM DBG ProxyAdmin contract already owned by this address
1:17PM DBG UniswapV3 deployed addresses={"FactoryV3":"0x517b35c144592801d8c91da672fe6beb72dbd53c","Migrator":"0xcde48557ee1e70f8d662cf5c1aa731802253f414","Multicall":"0xd05c6a5916d505210fd23d45ba01764e0f51f68d","NFTDescriptorLib":"0xd1aeb77784e6c963a53745f4ff987265e2eeb0d9","NonfungiblePositionManager":"0xed7b53de74e6fde98cf89e430a2a35871e34235a","NonfungibleTokenPositionDescriptor":"0x835b6433ffe0a67f2b0dc8c3be87d2c0594c985d","ProxyAdmin":"0x1e8eab39bb35a8e7fad0e83a8e58f8098d9e42cc","QuoterV2":"0x758a62abdbcabe2742164044e8cef24d9f962763","Staker":"0x3bb4c7ef05800ec62dc80e8dd0ed914cfadabee1","SwapRouter02":"0x09a1a871258aac7c894ecb3116fd1482b0a52c62","TickLens":"0xe16e25481168566a464283ad5c00499db046fbce","TransparentUpgradeableProxy":"0xd65144402b5162fc77a445d453d38ffcb7eeb54d","WETH9":"0x30ab089a1fd09798e331f65137c000e3cec3d0bc"}
1:17PM DBG 🪙 Deploying ERC20 tokens...
1:17PM DBG Contract deployed address=0xb8733537d194deab3eefd2425a9d3393110366f0 name=Swapper
1:17PM DBG Allowance set amount=999999999999999999 spenderAddress=0xed7b53de74e6fde98cf89e430a2a35871e34235a spenderName=NFTPositionManager tokenName=Swapper_SwapperA
1:17PM DBG Allowance set amount=999999999999999999 spenderAddress=0x09a1a871258aac7c894ecb3116fd1482b0a52c62 spenderName=SwapRouter02 tokenName=Swapper_SwapperA
1:17PM DBG Contract deployed address=0xf8ef62a588ffd92614f5011ae26fa4347ef04534 name=Swapper
1:17PM DBG Allowance set amount=999999999999999999 spenderAddress=0xed7b53de74e6fde98cf89e430a2a35871e34235a spenderName=NFTPositionManager tokenName=Swapper_SwapperB
1:17PM DBG Allowance set amount=999999999999999999 spenderAddress=0x09a1a871258aac7c894ecb3116fd1482b0a52c62 spenderName=SwapRouter02 tokenName=Swapper_SwapperB
1:17PM DBG 🎱 Deploying UniswapV3 liquidity pool...
1:17PM DBG Pool created and initialized fees=10000
1:17PM DBG Pool instantiated address=0x9c3d0ed03ecd5978e90b4736490ff08ad420129a
1:17PM DBG Liquidity provided to the pool liquidity=2000000000000
1:17PM DBG Starting main load test loop currentNonce=530
1:17PM ERR Unable to swap error="replacement transaction underpriced" amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM ERR Recorded an error while sending transactions error="replacement transaction underpriced" nonce=530
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Successful swap amountIn=100000 tokenIn=token0 tokenOut=token1
1:17PM DBG Successful swap amountIn=100000 tokenIn=token1 tokenOut=token0
1:17PM DBG Finished main load test loop currentNonce=550
1:17PM DBG Waiting for transactions to actually be mined
1:17PM INF rough test summary (ignores errors) final rate limit=4 firstBlockTime=2023-10-19T13:17:40+02:00 lastBlockTime=2023-10-19T13:17:50+02:00 testDuration=10 tps=2 transactionCount=20
1:17PM INF * Results
1:17PM INF Samples samples=20
1:17PM INF Start startTime=2023-10-19T13:17:41+02:00
1:17PM INF End endTime=2023-10-19T13:17:46+02:00
1:17PM INF Mean Wait meanWait=0.01955034585
1:17PM INF Num errors numErrors=1
1:17PM INF Finished

Here's how the help message looks like.

$ go run main.go loadtest uniswapv3 --help
The `uniswapv3` command is a subcommand of the `loadtest` tool. It is meant to generate UniswapV3-like load against JSON-RPC endpoints.

You can either chose to deploy the full UniswapV3 contract suite.

polycli loadtest uniswapv3 http://localhost:8545

Or to use pre-deployed contracts to speed up the process.

polycli loadtest uniswapv3 http://localhost:8545 \
  --uniswap-factory-v3-address 0xc5f46e00822c828e1edcc12cf98b5a7b50c9e81b \
  --uniswap-migrator-address 0x24951726c5d22a3569d5474a1e74734a09046cd9 \
  --uniswap-multicall-address 0x0e695f36ade2a12abea51622e80f105e125d1d6e \
  --uniswap-nft-descriptor-lib-address 0x23050ec03bb24308c788300428a8f9c247f28b25 \
  --uniswap-nft-position-descriptor-address 0xea43847a98b671211b0e412849b69bbd7d53fd00 \
  --uniswap-non-fungible-position-manager-address 0x58eabc23408fb7896b7ce943828cc00044786449 \
  --uniswap-proxy-admin-address 0xdba55eb96288eac85974376b25b3c3f3d67399b7 \
  --uniswap-quoter-v2-address 0x91464a00c4aae9dca6d503a2c24b1dfb8c279e50 \
  --uniswap-staker-address 0xc87383ece9ee3ad3f5158998c4fc04833ba1336e \
  --uniswap-swap-router-address 0x46096eb627d30125f9eaaeefeecaa4e237a04a97 \
  --uniswap-tick-lens-address 0xc73dfb5055874cc7b1cf06ae83f7fe8f6facdb19 \
  --uniswap-upgradeable-proxy-address 0x28656635b0ecd600801600475d61e3ec1534de6e \
  --weth9-address 0x5570d4fd7cce73f0135536d83b8d49e6b77bb76c \
  --uniswap-pool-token-0-address 0x1ce270d0380fbbead12371286aff578a1227d1d7 \
  --uniswap-pool-token-1-address 0x060f7db3146f3d6748822fb4c69489a04b5f3278

Contracts are cloned from the different Uniswap repositories, compiled with a specific version of `solc` and go bindings are generated using `abigen`. To learn more about this process, make sure to check out `contracts/uniswapv3/README.org`.

Usage:
  polycli loadtest uniswapv3 url [flags]

Flags:
  -h, --help                                                   help for uniswapv3
  -f, --pool-fees float                                        Trading fees charged on each swap or trade made within a UniswapV3 liquidity pool (e.g. 0.3 means 0.3%) (default 0.3)
  -a, --swap-amount uint                                       The amount of inbound token given as swap input (default 1000)
      --uniswap-factory-v3-address string                      The address of a pre-deployed UniswapFactoryV3 contract
      --uniswap-migrator-address string                        The address of a pre-deployed Migrator contract
      --uniswap-multicall-address string                       The address of a pre-deployed Multicall contract
      --uniswap-nft-descriptor-lib-address string              The address of a pre-deployed NFTDescriptor library contract
      --uniswap-nft-position-descriptor-address string         The address of a pre-deployed NonfungibleTokenPositionDescriptor contract
      --uniswap-non-fungible-position-manager-address string   The address of a pre-deployed NonfungiblePositionManager contract
      --uniswap-pool-token-0-address string                    The address of a pre-deployed ERC20 contract used in the Uniswap pool Token0 // Token1
      --uniswap-pool-token-1-address string                    The address of a pre-deployed ERC20 contract used in the Uniswap pool Token0 // Token1
      --uniswap-proxy-admin-address string                     The address of a pre-deployed ProxyAdmin contract
      --uniswap-quoter-v2-address string                       The address of a pre-deployed QuoterV2 contract
      --uniswap-staker-address string                          The address of a pre-deployed Staker contract
      --uniswap-swap-router-address string                     The address of a pre-deployed SwapRouter contract
      --uniswap-tick-lens-address string                       The address of a pre-deployed TickLens contract
      --uniswap-upgradeable-proxy-address string               The address of a pre-deployed TransparentUpgradeableProxy contract
      --weth9-address string                                   The address of a pre-deployed WETH9 contract

Global Flags:
      --adaptive-backoff-factor float              When using adaptive rate limiting, this flag controls our multiplicative decrease value. (default 2)
      --adaptive-cycle-duration-seconds uint       When using adaptive rate limiting, this flag controls how often we check the queue size and adjust the rates (default 10)
      --adaptive-rate-limit                        Enable AIMD-style congestion control to automatically adjust request rate
      --adaptive-rate-limit-increment uint         When using adaptive rate limiting, this flag controls the size of the additive increases. (default 50)
      --batch-size uint                            Number of batches to perform at a time for receipt fetching. Default is 999 requests at a time. (default 999)
      --call-only                                  When using this mode, rather than sending a transaction, we'll just call. This mode is incompatible with adaptive rate limiting, summarization, and a few other features.
      --call-only-latest                           When using call only mode with recall, should we execute on the latest block or on the original block
      --chain-id uint                              The chain id for the transactions.
  -c, --concurrency int                            Number of requests to perform concurrently. Default is one request at a time. (default 1)
      --config string                              config file (default is $HOME/.polygon-cli.yaml)
      --contract-call-block-interval uint          During deployment, this flag controls if we should check every block, every other block, or every nth block to determine that the contract has been deployed (default 1)
      --contract-call-nb-blocks-to-wait-for uint   The number of blocks to wait for before giving up on a contract deployment (default 30)
      --gas-limit uint                             In environments where the gas limit can't be computed on the fly, we can specify it manually. This can also be used to avoid eth_estimateGas
      --gas-price uint                             In environments where the gas price can't be determined automatically, we can specify it manually
  -i, --iterations uint                            If we're making contract calls, this controls how many times the contract will execute the instruction in a loop. If we are making ERC721 Mints, this indicates the minting batch size (default 1)
      --legacy                                     Send a legacy transaction instead of an EIP1559 transaction.
      --output-mode string                         Format mode for summary output (json | text) (default "text")
      --pretty-logs                                Should logs be in pretty format or JSON (default true)
      --priority-gas-price uint                    Specify Gas Tip Price in the case of EIP-1559
      --private-key string                         The hex encoded private key that we'll use to send transactions (default "42b6e34dc21598a807dc19d7784c71b2a7a01f6480dc6f58258f78e539f1a1fa")
      --rate-limit float                           An overall limit to the number of requests per second. Give a number less than zero to remove this limit all together (default 4)
  -n, --requests int                               Number of requests to perform for the benchmarking session. The default is to just perform a single request which usually leads to non-representative benchmarking results. (default 1)
      --seed int                                   A seed for generating random values and addresses (default 123456)
      --send-amount string                         The amount of wei that we'll send every transaction (default "0x38D7EA4C68000")
      --steady-state-tx-pool-size uint             When using adaptive rate limiting, this value sets the target queue size. If the queue is smaller than this value, we'll speed up. If the queue is smaller than this value, we'll back off. (default 1000)
      --summarize                                  Should we produce an execution summary after the load test has finished. If you're running a large load test, this can take a long time
  -t, --time-limit int                             Maximum number of seconds to spend for benchmarking. Use this to benchmark within a fixed total amount of time. Per default there is no time limit. (default -1)
      --to-address string                          The address that we're going to send to (default "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
      --to-random                                  When doing a transfer test, should we send to random addresses rather than DEADBEEFx5
  -v, --verbosity int                              0 - Silent
                                                   100 Fatal
                                                   200 Error
                                                   300 Warning
                                                   400 Info
                                                   500 Debug
                                                   600 Trace (default 400)

@leovct
Copy link
Member Author

leovct commented Oct 19, 2023

Done cleaning up and documenting the code :)

Copy link
Member

@praetoriansentry praetoriansentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!!!! NICE

@leovct leovct merged commit 8a40b24 into main Oct 20, 2023
5 checks passed
@leovct leovct deleted the jhilliard/feat/uniswap-loadtest branch October 20, 2023 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants